/*
 * Copyright © Yan Zhenjie. All Rights Reserved
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.iotimc.attendancesystem.server.response;

import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Environment;
import android.text.TextUtils;
import android.util.Log;

import com.alibaba.fastjson.JSON;
import com.iotimc.attendancesystem.App;
import com.iotimc.attendancesystem.dao.GreenDaoManager;
import com.iotimc.attendancesystem.dao.SystemEntityDao;
import com.iotimc.attendancesystem.entity.SystemEntity;
import com.iotimc.attendancesystem.event.NoticeEvent;
import com.iotimc.networklibrary.entity.BaseEntity;
import com.yanzhenjie.andserver.RequestHandler;
import com.yanzhenjie.andserver.upload.HttpFileUpload;
import com.yanzhenjie.andserver.upload.HttpUploadContext;
import com.yanzhenjie.andserver.util.HttpRequestParser;

import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileItemFactory;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.http.HttpEntityEnclosingRequest;
import org.apache.http.HttpException;
import org.apache.http.HttpRequest;
import org.apache.http.HttpResponse;
import org.apache.http.entity.StringEntity;
import org.apache.http.protocol.HttpContext;
import org.greenrobot.eventbus.EventBus;

import java.io.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import io.reactivex.Observable;
import io.reactivex.functions.Consumer;
import io.reactivex.schedulers.Schedulers;

/**
 * <p>Upload file handler.</p>
 * Created by Yan Zhenjie on 2016/6/13.
 *
 * @author cwj
 */
public class RequestUploadHandler implements RequestHandler {
    private boolean UUID, noticeEvent;
    private SystemEntity load;
    private SystemEntityDao systemEntityDao;
    private BaseEntity mBaseEntity;

    @Override
    public void handle(HttpRequest request, HttpResponse response, HttpContext context) throws HttpException, IOException {

        mBaseEntity = new BaseEntity();
        systemEntityDao = GreenDaoManager.getInstance().getSession().getSystemEntityDao();
        load = systemEntityDao.load(1L);

        if (load == null) {
            load = new SystemEntity();
        }

        if (!HttpFileUpload.isMultipartContentWithPost(request)) {
            //没有上传file
            Map<String, String> params = HttpRequestParser.parse(request);
            setEntity(params);
        } else {
            // 请求里包含file
            final File saveDirectory = Environment.getExternalStorageDirectory();
            if (saveDirectory.isDirectory()) {
                try {
                    processFileUpload(request, saveDirectory);
                } catch (Exception e) {
                    e.printStackTrace();
                    uploadApk = false;
                    error.add("Save the file when the error occurs.");
                }
            } else {
                error.add("The server can not save the file.");
            }
        }

        if (UUID) {
            if (error.size() < 1) {
                if (mBaseEntity == null) {
                    mBaseEntity = new BaseEntity();
                }
                mBaseEntity.setStatus("0");
                mBaseEntity.setResult(load);
                response(200, JSON.toJSONString(mBaseEntity), response);
            } else {
                if (mBaseEntity == null) {
                    mBaseEntity = new BaseEntity();
                }
                mBaseEntity.setStatus("1");
                mBaseEntity.setMessage(error.toString());
                response(200, JSON.toJSONString(mBaseEntity), response);
            }
            error.clear();

            if (systemEntityDao.load(1L) == null) {
                if (noticeEvent) {
                    systemEntityDao.insert(load);
                    EventBus.getDefault().post(new NoticeEvent(true));
                }
            } else {
                if (noticeEvent) {
                    systemEntityDao.update(load);
                    EventBus.getDefault().post(new NoticeEvent(true));
                }
            }
            noticeEvent = false;

            if (uploadApk) {
                Observable.just(1)
                        .subscribeOn(Schedulers.io())
                        .observeOn(Schedulers.io())
                        .subscribe(new Consumer<Integer>() {
                            @Override
                            public void accept(Integer integer) throws Exception {
                                installApk();
                                uploadApk = false;
                            }
                        });
            }
        } else {
            if (mBaseEntity == null) {
                mBaseEntity = new BaseEntity();
            }
            mBaseEntity.setStatus("1");
            mBaseEntity.setMessage("需要管理员登录");
            response(200, JSON.toJSONString(mBaseEntity), response);
        }

    }

    private void response(int responseCode, String message, HttpResponse response) throws IOException {
        response.setStatusCode(responseCode);
        response.setEntity(new StringEntity(message, "utf-8"));
    }

    /**
     * Parse file and save.
     *
     * @param request       request.
     * @param saveDirectory save directory.
     * @throws Exception may be.
     */
    private boolean uploadApk;

    private void processFileUpload(HttpRequest request, File saveDirectory) throws Exception {
        FileItemFactory factory = new DiskFileItemFactory(1024 * 1024, saveDirectory);
        HttpFileUpload fileUpload = new HttpFileUpload(factory);
        List<FileItem> fileItems = fileUpload.parseRequest(new HttpUploadContext((HttpEntityEnclosingRequest) request));

        checkUUID(fileItems);
        if (UUID) {
            for (FileItem fileItem : fileItems) {
                long size = fileItem.getSize();
                //存数据库,限制小于2mb
                if (size > 2048000 && fileItem.isFormField()) {
                    error.add("The server can not save the " + fileItem.getName() + ".");
                } else {
                    //文件
                    if (!fileItem.isFormField()) {
                        String name = fileItem.getName();
                        if ("apk".equals(fileItem.getFieldName()) && fileItem.getSize() > 0) {
                            name = "attendance.apk";
                            uploadApk = true;
                        }
                        if ("img".equals(fileItem.getFieldName()) && fileItem.getSize() > 0) {
                            File directory = Environment.getExternalStorageDirectory();
                            File[] files = directory.listFiles();

                            for (File file : files) {
                                if (file.getName().contains("attendanceImg")) {
                                    file.delete();
                                }
                            }
                            name = "attendanceImg" + name.substring(name.lastIndexOf("."));
                        }
                        File uploadedFile = new File(saveDirectory, name);
                        // 把流写到文件上。
                        if (fileItem.getSize() > 0) {
                            fileItem.write(uploadedFile);
                        }
                    } else {
                        //表单信息
                        setEntity(fileItem);
                    }
                }
            }
        }


    }

    private boolean checkUUID(List<FileItem> items) {
        for (FileItem fileItem : items) {
            String key = fileItem.getFieldName();
            String value = fileItem.getString();
            String decode = decode(value);
            if ("UUID".equals(key)) {
                String appUuid = App.getInstance().getCookie();
                if (!TextUtils.isEmpty(appUuid)) {
                    if (decode.contains(appUuid)) {
                        UUID = true;
                        return true;
                    }
                }
            }
        }
        UUID = false;
        return false;
    }

    private ArrayList<String> error = new ArrayList<>();

    private void setEntity(FileItem fileItem) {
        String key = fileItem.getFieldName();
        String value = fileItem.getString();
        String decode = null;
        try {
            decode = new String(value.getBytes("ISO8859_1"), "utf-8");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }

        if (decode != null && UUID && !TextUtils.isEmpty(key)) {
            switch (key) {
                case "content":
                    load.setContent(decode);
                    noticeEvent = true;
                    break;
                case "img64":
                    load.setImg64(decode.substring(decode.indexOf(',') + 1));
                    noticeEvent = true;
                    break;
                case "title":
                    load.setTitle(decode);
                    noticeEvent = true;
                    break;
                case "message":
                    load.setNotice(decode);
                    noticeEvent = true;
                    break;
                default:
                    break;
            }
        }
    }

    private void setEntity(Map<String, String> params) {
        String uuid = params.get("UUID");
        String appUuid = App.getInstance().getCookie();
        if (!TextUtils.isEmpty(appUuid)) {
            if (!TextUtils.isEmpty(uuid) && uuid.contains(appUuid)) {
                UUID = true;
                String content = params.get("content");
                String img64 = params.get("img64");
                String title = params.get("title");
                String message = params.get("message");

                if (!TextUtils.isEmpty(content)) {
                    String decode = decode(content);
                    load.setContent(decode);
                    noticeEvent = true;
                }

                if (!TextUtils.isEmpty(img64)) {
                    String decode = decode(img64);
                    img64 = decode.substring(decode.indexOf(',') + 1);
                    Log.i(TAG, "setEntity: " + decode);
                    load.setImg64(img64);
                    noticeEvent = true;
                }

                if (!TextUtils.isEmpty(title)) {
                    String decode = decode(title);
                    load.setTitle(decode);
                    noticeEvent = true;
                }

                if (!TextUtils.isEmpty(message)) {
                    String decode = decode(message);
                    load.setNotice(decode);
                    noticeEvent = true;
                }
            } else {
                UUID = false;
            }
        }


    }

    private String decode(String info) {
        String decode = "";
        try {
            decode = URLDecoder.decode(info, "utf-8");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }

        return decode;
    }

    private void installApk() {
        File file1 = new File(Environment.getExternalStorageDirectory(), "attendance.apk");
        PackageInfo apkgInfo = App.getAppContext().getPackageManager().getPackageArchiveInfo(file1.getPath(), PackageManager.GET_ACTIVITIES);
        if (apkgInfo != null) {
            //下载的apk
            int upgradeCode = apkgInfo.versionCode;
            String name = apkgInfo.versionName;
            String name1 = apkgInfo.packageName;

            try {
                String pkName = App.getAppContext().getPackageName();
                String name2 = App.getAppContext().getPackageManager().getPackageInfo(pkName, PackageManager.GET_ACTIVITIES).versionName;
                int versionCode = App.getAppContext().getPackageManager().getPackageInfo(pkName, 0).versionCode;

                if (name1.equals(pkName) && upgradeCode >= versionCode) {
                    Intent intent = new Intent(Intent.ACTION_VIEW);
                    File file = new File(Environment.getExternalStorageDirectory(), "attendance.apk");
                    //如果没有设置SDCard写权限，或者没有sdcard,apk文件保存在内存中，需要授予权限才能安装
                    try {
                        String[] command = {"chmod", "777", file.toString()};
                        ProcessBuilder builder = new ProcessBuilder(command);
                        builder.start();
                    } catch (IOException ignored) {
                    }
                    intent.setDataAndType(Uri.fromFile(file), "application/vnd.android.package-archive");

                    intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                    App.getAppContext().startActivity(intent);
                }
            } catch (PackageManager.NameNotFoundException e) {
                e.printStackTrace();
            }
        }


    }

    private static final String TAG = "RequestUploadHandler";
}
